AddCSLuaFile( "PP_client.lua" )
AddCSLuaFile( "PP_limits.lua" )
AddCSLuaFile( "PP_friends.lua" )
AddCSLuaFile( "PP_shared.lua" )
AddCSLuaFile( "PPInfo.lua" )
AddCSLuaFile( "MapMenu.lua" )
AddCSLuaFile( "MapTimer.lua" )

include( "server.lua" )
include( "PP_shared.lua" )
include( "inventory_shared.lua" )



ETable = {}
IdleTable = {}


PLAYER = FindMetaTable( "Player" )

function PLAYER:RANK()
	return self:GetNetworkedString( "rank" )
end 

function PLAYER:FLAGS()
	return self:GetNetworkedString( "flags" )
end

PLAYER = nil

function InitETable( ply )

	if ETable[ply:UniqueID()] then
		timer.Destroy( ply:UniqueID() .. "RemoveTimer" )
		
		for k,v in pairs( ETable[ply:UniqueID()] ) do
			if k != "NEXTSPAWN" and k != "MULTI" and v and v:IsValid() then
				v:SetNWString( "owner", ply:UniqueID() )
				v:SetNWEntity( "clOwner", ply )
			end
		end
		ETable[ply:UniqueID()].NEXTSPAWN = 0
		ETable[ply:UniqueID()].MULTI = 0
	else
		ETable[ply:UniqueID()] = {}
		ETable[ply:UniqueID()].NEXTSPAWN = 0
		ETable[ply:UniqueID()].MULTI = 0
		print( "TABLE CREATE" )
		PrintTable( ETable )
	end
	
	IdleTable[ply:UniqueID()] = {}
	IdleTable[ply:UniqueID()].ITime = nil
	IdleTable[ply:UniqueID()].EAngles = ply:EyeAngles()
	
end
hook.Add( "PlayerInitialSpawn", "InitETable", InitETable )

function PlyTimerDC( ply )
	print( "DC :" .. ply:UniqueID() )
	timer.Create( ply:UniqueID() .. "RemoveTimer", RemovePropsDelay, 1, RemoveProps, ply:UniqueID(), ply:Nick() )
	local rp = RecipientFilter()
	rp:AddAllPlayers()
				
	umsg.Start( "DCMessage", rp )
		umsg.String( ply:Nick() )
	umsg.End()
end
hook.Add( "PlayerDisconnected", "PlyTimerDC", PlyTimerDC )

function RemoveProps( UID, Nick )
	local rp = RecipientFilter()
	rp:AddAllPlayers()
				
	umsg.Start( "RemoveMessage", rp )
		umsg.String( Nick )
	umsg.End()
	
	for k,v in pairs( ETable[UID] ) do
		if k != "NEXTSPAWN" and k != "MULTI" and v and v:IsValid() then v:Remove() end
	end
	ETable[UID] = nil
end

function IdleCheck()		//fix this.
	for k,v in pairs( player.GetAll() ) do
	if string.find( v:GetNetworkedString( "flags" ), "D" ) then break end
		local EA = v:EyeAngles()
		
		if IdleTable[v:UniqueID()] and IdleTable[v:UniqueID()].EAngles == EA and IdleTable[v:UniqueID()].ITime != nil then
			if CurTime() >= IdleTable[v:UniqueID()].ITime then
				RunConsoleCommand( "kickid", v:UserID(), "Kicked for idling." )
				IdleTable[v:UniqueID()] = nil
				
				local rp = RecipientFilter()
				rp:AddAllPlayers()
				
				umsg.Start( "IdleMessage", rp )
					umsg.String( v:Nick() )
				umsg.End()
			end
		elseif IdleTable[v:UniqueID()] and IdleTable[v:UniqueID()].EAngles == EA and IdleTable[v:UniqueID()].ITime == nil then
			IdleTable[v:UniqueID()].ITime = CurTime() + IdleKickTime
		elseif IdleTable[v:UniqueID()] and IdleTable[v:UniqueID()].ITime != nil then
			IdleTable[v:UniqueID()].ITime = nil
			IdleTable[v:UniqueID()].EAngles = nil
		end
		if IdleTable[v:UniqueID()] then IdleTable[v:UniqueID()].EAngles = EA end
	end
end
hook.Add( "Tick", "IdleCheck", IdleCheck )


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adding props to the tables and manipulating the tables here.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
function AddOwner( ply, ent, Type )	//Use Type to check if it is a duplicate, and ignore the spam  protection
	if !ent or !ent:IsValid() or ent == NullEntity then return end
	ent:SetNWString( "owner", ply:UniqueID() )
	ent:SetNWEntity( "clOwner", ply )
	
	print( Type )
	
	if CurTime() < ETable[ply:UniqueID()].NEXTSPAWN and Type == "props" then
		ply:SendLua( "GAMEMODE:AddNotify( \"Wait a few seconds before spawning something else.\", 1, 5 ) surface.PlaySound( \"Resource/warning.wav\" )" )
		CheckRemoved( ent ) ent:Remove()
	else
		ETable[ply:UniqueID()].NEXTSPAWN = CurTime() + SpawnDelay
		print( ent:GetClass() )

		print( type( ETable[ply:UniqueID()] ) )
		for k,v in pairs( LimitsTable ) do
			if v == ent:GetClass() and !table.HasValue( ETable[ply:UniqueID()], ent ) then table.insert( ETable[ply:UniqueID()], ent ) break end
		end
	
		CheckItem( ply, ent )
	end
end

function CheckItem( ply, ent )
	print( "CHECK DUPED" )
	local LIMIT = ReadLimits[ply:RANK()][ent:GetClass()]
	local COUNT = 0
	
	for k,v in pairs( ETable[ply:UniqueID()] ) do
		if k != "NEXTSPAWN" and k != "MULTI" and v != NullEntity and v != nil and v:IsValid() then
			if v:GetClass() == ent:GetClass() then COUNT = COUNT + 1 end
		end
	end
	print( LIMIT .. ": " .. COUNT )
	if COUNT > tonumber(LIMIT) then NotifyErr( ply, ent:GetClass() ) CheckRemoved( ent ) ent:Remove() end
end
 
function CheckRemoved( ent )	//Change this to a single loop, removing all nil entities
	local OWN = player.GetByUniqueID( ent:GetNWString( "owner" ) )
	if OWN and OWN:IsValid() then
	print( "ENTITY REMOVED" )
	print( OWN:Nick() )
	
	ETable[OWN:UniqueID()].MULTI = ETable[OWN:UniqueID()].MULTI + 1
	print( ETable[OWN:UniqueID()].MULTI )
	timer.Create( "LREMOVE", 2, 1, LoopRemove, ent, OWN )
	
	
	end
end
hook.Add( "EntityRemoved", "CheckRemoved", CheckRemoved )

function LoopRemove( ent, OWN )		//New way of progressive looping through list.

	if ETable[OWN:UniqueID()].MULTI >= 30 then
		local NET = {}
		for k,v in pairs( ents.GetAll() ) do
			if player.GetByUniqueID( v:GetNWString( "owner" ) ) == OWN then
				table.insert( NET, v )
			end
		end
		ETable[OWN:UniqueID()] = NET
		ETable[OWN:UniqueID()].MULTI = 0
		ETable[OWN:UniqueID()].NEXTSPAWN = CurTime()
	else
		for k,v in pairs( ETable[OWN:UniqueID()] ) do
			if type(k) == "number" then
				if v == NullEntity or v == nil or !v:IsValid() then
					ETable[OWN:UniqueID()][k] = nil
					ETable[OWN:UniqueID()].MULTI = ETable[OWN:UniqueID()].MULTI - 1
					PrintTable( ETable[OWN:UniqueID()] )
				end
			end
		end
	end

end

if(cleanup) then
	local Clean = cleanup.Add
	function cleanup.Add(Player, Type, Entity)
		if(Entity) then
			local Check = Player:IsPlayer()
			local Valid = Entity:IsValid()
		    if(Check and Valid) then
				print("OWNER ADDED")
		        AddOwner(Player, Entity, Type)
		    end
		end
	    Clean(Player, Type, Entity)
	end
end

function NotifyErr( ply , etype )
	ply:SendLua( "GAMEMODE:AddNotify( \"You have reached your rank's " .. etype .. " limit\", 1, 5 ) surface.PlaySound( \"Resource/warning.wav\" )" )
end

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Physgun and Tool blocking
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
function FriendCheck( ply, ent )	//Add timer checks here.
	local OWN = player.GetByUniqueID( ent:GetNWString( "owner" ) )
	if ent:IsValid() and OWN and OWN:IsValid() and !string.find( ply:GetNetworkedString( "flags" ), "O" ) then
		if !ent:IsPlayer() then
			return table.HasValue( FriendsTable[OWN:UniqueID()], ply )
		end
	else
		return false
	end
end

function BlockPhysGravGun( ply, ent )
	local OWN = player.GetByUniqueID( ent:GetNWString( "owner" ) )
	if string.find( ply:GetNetworkedString( "flags" ), "O" ) then
		return true
	elseif (OWN == ply or FriendCheck( ply, ent )) and !ent:IsPlayer() then
		return true
	else
		//ply:SendLua( "GAMEMODE:AddNotify( \"This entity does not belong to you\", 1, 5 ) surface.PlaySound( \"Resource/warning.wav\" )" )
	return false end

end
hook.Add( "PhysgunPickup", "BlockPhysGravGun", BlockPhysGravGun ) 
hook.Add( "GravGunPickupAllowed", "BlockPhysGravGun", BlockPhysGravGun ) 
hook.Add( "GravGunPunt", "BlockPhysGravGun", BlockPhysGravGun )
hook.Add( "CanPlayerUnfreeze", "BlockPhysGravGun", BlockPhysGravGun )

function BlockTool( ply, tr, toolmode )
	print( toolmode )
	if tr.Entity:IsValid() then
	local OWN = player.GetByUniqueID( tr.Entity:GetNWString( "owner" ) )
		if OWN == ply or FriendCheck( ply, tr.Entity ) or string.find( ply:GetNetworkedString( "flags" ), "O" ) then
			return true
		else
			ply:SendLua( "GAMEMODE:AddNotify( \"This entity does not belong to you\", 1, 5 ) surface.PlaySound( \"Resource/warning.wav\" )" )
			return false
		end
	end
	
	if CurTime() < ETable[ply:UniqueID()].NEXTSPAWN and (toolmode == "duplicator" or toolmode == "adv_duplicator") then
		ply:SendLua( "GAMEMODE:AddNotify( \"Wait a few seconds before using a tool.\", 1, 5 ) surface.PlaySound( \"Resource/warning.wav\" )" )
		return false
	end
	
	if toolmode != "ol_stacker" then
		ETable[ply:UniqueID()].NEXTSPAWN = CurTime() + SpawnDelay
	end
end
hook.Add( "CanTool", "BlockTool", BlockTool )

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Map Changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
function StreamMaps( ply, command, args)
	local DATA = file.Find( "../maps/*.bsp" )

	datastream.StreamToClients( { ply }, "MAPSTREAM", { DATA } )
end
concommand.Add( "StreamMaps", StreamMaps )

function ShowMapTimer( ply, command, args )
	local rp = RecipientFilter()
	rp:AddAllPlayers()
	
	umsg.Start( "MapTimerMESS", rp )
		umsg.String( args[1] )
		umsg.Long( tonumber(args[2]) )
		if args[3] == "REMOVE" then umsg.Bool( true ) else umsg.Bool( false ) end
	umsg.End()
end
concommand.Add( "ShowMapTimer", ShowMapTimer )

function DoChangeLevel( ply, command, args )

	if string.find( ply:GetNetworkedString( "flags" ), "A" ) then
		game.ConsoleCommand( "changelevel " .. args[1] .. "\n" )
	else
		ply:PrintMessage( HUD_PRINTTALK, "You lack the necessary flags to changelevel.(A)" )
	end
end
concommand.Add( "DoChangeLevel", DoChangeLevel )